﻿// Serotonin -- easy-to-use image filters application
// https://code.google.com/p/serotonin/
//
// Copyright © Frank Nagl, 2012-2013
// admin@franknagl.de
//
namespace Serotonin
{
    using Helper;
    using OptionsForms;
    using Controls;
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Globalization;
    using System.IO;
    using System.Windows.Forms;

    /// <summary>
    /// Main form of the application ShaderBasedImageProcessor.
    /// </summary>
    public partial class MainForm : Form
    {
        private ImageSketchManager imageSketchManager;

        // determines, if old version is updateable
        private bool isUpdateable;        
        private GroupBox options;
        /// <summary>
        /// Factor for multiplying cursor's X-coordinate at <see cref="panel"/> 
        /// to get correct image pixel coordinate.
        /// </summary>
        private float scaleCursorX;
        /// <summary>
        /// Factor for multiplying cursor's Y-coordinate at <see cref="panel"/> 
        /// to get correct image pixel coordinate.
        /// </summary>
        private float scaleCursorY;
        private Processor processor;
        private readonly SaveImageDialogForm saveImageDialogForm;

        /// <summary>
        /// Initializes a new instance of the <see cref="MainForm"/> class.
        /// </summary>
        /// <param name="useUpdater">If set to <c>true</c> the autoupdater is 
        /// used.</param>
        protected MainForm(bool useUpdater)
        {
            InitializeComponent();
            options = new GroupBox();
            saveImageDialogForm = new SaveImageDialogForm();

            SetStrings();

            if (!useUpdater)
            {
                return;
            }

            AutoUpdater updater = new AutoUpdater(
                Program.OptionsFile,
                "http://franknagl.de/updates/Serotonin/update.csv",
                Program.ProgramPath,
                Program.ProgramExe);
            updater.OnCheckUpdateEvent += UpdateAvailable;
            updater.CheckUpdateAsThread();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MainForm"/> class.
        /// </summary>
        public MainForm()
            : this(true)
        {
            Initialize(null);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MainForm"/> class.
        /// </summary>
        /// <param name="filename">The passed image or video filename.</param>
        public MainForm(string filename)
            : this(true)
        {
            Initialize(filename);
        }

        #region private methods

        private void InfoToolStripMenuItemClick(object sender, EventArgs e)
        {
            new InfoForm().Show(this);
        }

        private void Initialize(string filename)
        {
            Bitmap b;      
            if (filename == null)
            {
                Text = Program.OptionsPath + "\\black.png";
                b = new Bitmap(180, 180, PixelFormat.Format24bppRgb);
                b.Save(Text, ImageFormat.Png);
                // Hack, for correct start height in SetPanelSize(..) method      
                options.Height = 620;         
            }
            else
            {
                Text = filename;
                FileInfo info = new FileInfo(filename);
                string ext = info.Extension.ToLower();

                switch (ext)
                {
                    case ".wmf":
                    case ".tiff":
                    case ".tif":
                    case ".gif":
                    case ".emf":
                    case ".png":
                    case ".bmp":
                    case ".jpeg":
                    case ".jpg":
                        //LoadImage(filename);
                        b = new Bitmap(filename);
                        break;
                    default:
                        if (MessageBox.Show(Program.L.Text[12], Program.L.Text[13],
                                    MessageBoxButtons.YesNo) == DialogResult.Yes)
                        {
                            Initialize(null);
                            return;
                        }
                        
                        Dispose();  // close Serotonin
                        return;
                }
            }

            b = BitmapConverter.To24Bpp(b);
            SetPanelSize(b.Width, b.Height);

            // read in property 'RealtimeProcessing'
            string s = IOFile.ReadLine(Program.OptionsFile, 3);
            s = s.Substring(s.IndexOf(';') + 1);
            bool savedRealtimeProcessing = Boolean.Parse(s);  

            processor = new Processor(b, Text, panel);            
            InitOptions(new OriginalForm(processor).Options, true);
            cbRealtimeProcessing.Checked = savedRealtimeProcessing;
            processor.RealtimeProcessing = savedRealtimeProcessing;
            processor.GbProcess.Enabled = !savedRealtimeProcessing;
            saveImageDialogForm.SetProcessor(processor);

            
        }

        private void InitOptions(GroupBox groupBox, bool enableGbRealtimeProcessing)
        {          
            Point loc = options.Location;
            Controls.Remove(options);
            options.Dispose();
            options = groupBox;
            options.Location = loc;
            Controls.Add(options);

            // setting postion of dimensions group box
            gbInfos.Location = new Point(
                options.Location.X, options.Location.Y + options.Height + 10);

            // setting postion of realtime processing group box
            gbRealtimeProcessing.Location = new Point(
                gbInfos.Location.X, gbInfos.Location.Y + gbInfos.Height + 10);

            gbRealtimeProcessing.Enabled = enableGbRealtimeProcessing;
            if (!enableGbRealtimeProcessing)
            {
                processor.GbProcess.Enabled = true;
                // remove, if not realtime-able
                processor.RemoveAllApplyEvents();
            }

            processor.Reset();
            processor.ApplyFilterRTP();
        }

        private void SetPanelSize(int w, int h)
        {
            const int optionsWidth = 390;
            const int realtimeProcHeight = 40;
            Location = new Point(0, 0);
            Size maxSize = new Size(
                    SystemInformation.PrimaryMonitorSize.Width,
                    SystemInformation.PrimaryMonitorSize.Height - 45);
            int panelW = SystemInformation.PrimaryMonitorSize.Width - optionsWidth;
            int panelH = SystemInformation.PrimaryMonitorSize.Height - 135;

            if (panelW < w || panelH < h)
            {
                bool wLonger = (w / (float)h) > (panelW / (float)panelH);
                if (wLonger)
                {
                    panelH = h * panelW / w;
                    maxSize.Height = panelH + 170 + realtimeProcHeight + panel.Location.Y;
                }
                else
                {
                    panelW = w * panelH / h;
                    maxSize.Width = panelW + optionsWidth + panel.Location.X;
                }
                panel.Size = new Size(panelW, panelH);
                Size = maxSize;
            }
            else
            {
                panel.Size = new Size(w, h);
                Size = new Size(
                    w + optionsWidth + panel.Location.X,
                    h + 170 + realtimeProcHeight + panel.Location.Y);
            }

            // check, if windows is high enough, so complete options are visible
            if (panel.Size.Height < options.Height + 50 + panel.Location.Y)
            {
                Height = options.Height + 200 + panel.Location.Y;
                // avoid over height, when very small resolution
                Height = Math.Min(
                    Height, SystemInformation.PrimaryMonitorSize.Height - 45);
            }

            options.Location = new Point(panel.Size.Width + 30, 30);

            // setting image informations
            scaleCursorX = w / (float)panel.Size.Width;
            scaleCursorY = h / (float)panel.Size.Height;
            lbWidth.Text = w.ToString(CultureInfo.InvariantCulture);
            lbHeight.Text = h.ToString(CultureInfo.InvariantCulture);
        }

        private void SetStrings()
        {
            FileToolStripMenuItem.Text = Program.L.Text[0];
            tsItmOpenImage.Text = Program.L.Text[1];
            SaveAsToolStripMenuItem.Text = Program.L.Text[2];
            QuitToolStripMenuItem.Text = Program.L.Text[3];
            RealtimeCapableFilterToolStripMenuItem.Text = Program.L.Text[4];
            NotRealtimeCapableFilterToolStripMenuItem.Text = Program.L.Text[5];
            NoFilterToolStripMenuItem.Text = Program.L.Text[6];
            oilPaintingToolStripMenuItem.Text = Program.L.Text[7];
            coloredCannyEdgeDetectorToolStripMenuItem.Text = Program.L.Text[8];            
            congrapContourTracerToolStripMenuItem.Text = Program.L.Text[9];
            imageSketchesToolStripMenuItem.Text = Program.L.Text[10];
            splitColorSpaceChannelsToolStripMenuItem.Text = Program.L.Text[11];
            gaussianBlurToolStripMenuItem.Text = Program.L.Text[105];
            gbInfos.Text = Program.L.Text[18];
            lbWidthText.Text = Program.L.Text[19];
            lbHeightText.Text = Program.L.Text[20];
            gbRealtimeProcessing.Text = Program.L.Text[21];
            cbRealtimeProcessing.Text = Program.L.Text[22];
            ColoredSobelToolStripMenuItem.Text = Program.L.Text[25];
            GrayscaleToolStripMenuItem.Text = Program.L.Text[83];
            ExtractOrRotateChannelsToolStripMenuItem.Text = Program.L.Text[89];
            ExponentiateChannelsToolStripMenuItem.Text = Program.L.Text[91];
            ThresholdFilterAndBinaryImageToolStripMenuItem.Text = Program.L.Text[98];
            colorSegmentationToolStripMenuItem.Text = Program.L.Text[107];
            meanShiftToolStripMenuItem.Text = Program.L.Text[120];
            Convolution5x5ToolStripMenuItem.Text = Program.L.Text[125];
            UnSharpMaskingToolStripMenuItem.Text = Program.L.Text[135];            
        }

        private void UpdateAvailable(bool updateable)
        {
            UpdateToolStripMenuItem.Visible = true;
            isUpdateable = updateable;
        }

        #region Open-Save-Close-Update GUI events

        private void SaveAsToolStripMenuItemClick(object sender, EventArgs e)
        {
            saveImageDialogForm.Show();
        }

        private void TsItmOpenImageClick(object sender, EventArgs e)
        {
            openFileDialog.Filter = Program.L.Text[14];
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                Initialize(openFileDialog.FileName);                
            }
        }

        private void UpdateToolStripMenuItemClick(object sender, EventArgs e)
        {
            if (isUpdateable)
            {
                if (MessageBox.Show(
                    Program.L.Text[15],
                    Program.L.Text[16],
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    VistaSecurity.RestartElevatedForUpdate();
                }
            }
            else
            {
                if (MessageBox.Show(
                    Program.L.Text[17],
                    Program.L.Text[16],
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    System.Diagnostics.Process.Start("https://code.google.com/p/serotonin/");
                }
            }
        }

        private void QuitToolStripMenuItemClick(object sender, EventArgs e)
        {
            Close();
        }

        #endregion Open-Save-Close-Update GUI events

        #region Filter ToolStrip MenuItem Events
        private void NoFilterToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new OriginalForm(processor).Options, true);
        }

        private void OilPaintingToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new OilPaintingForm(processor).Options, false);
        }

        private void UnSharpMaskingToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new UnSharpMaskingForm(processor).Options, false);
        }

        private void Convolution5X5ToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new ConvolutionForm(processor).Options, false);
        }

        private void ChessboardToolStripMenuItemClick(object sender, EventArgs e)
        {
            // InitOptions(new ChessboardForm(processor).Options);
        }

        private void ExtractOrRotateChannelsToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new ExtractOrRotateChannelsForm(processor).Options, true);
        }

        private void InvertToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new InvertForm(processor).Options, true);
        }

        private void GaussianBlurToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new GaussianBlurForm(processor).Options, false);
        }

        private void GrayscaleToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new GrayscaleForm(processor).Options, true);
        }

        private void PosterizationToolStripMenuItemClick(object sender, EventArgs e)
        {
            // InitOptions(new PosterizationForm(processor).Options);
        }

        private void SepiaToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new SepiaForm(processor).Options, true);
        }

        private void ColoredSobelToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new ColoredSobelForm(processor).Options, true);
        }

        private void ExponentiateChannelsToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new ExponentiateChannelsForm(processor).Options, true);
        }

        private void ThresholdAndBinarizationToolStripMenuItemClick(
            object sender, EventArgs e)
        {
            InitOptions(new ThresholdAndBinarizationForm(processor).Options, true);
        }

        private void MeanShiftToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new MeanshiftForm(processor).Options, false);
        }
        #endregion Filter ToolStrip MenuItem Events


        #region Scientific filters ToolStrip MenuItem Events

        private void ColoredCannyEdgeDetectorToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new ColoredCannyForm(processor).Options, true);
        }

        private void ConTrapContourTracerToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new ConGrapForm(processor).Options, false);
        }

        #region ImageSketches
        private void ImageSketchesToolStripMenuItemClick(object sender, EventArgs e)
        {
            imageSketchManager = new ImageSketchManager(
                processor, panel.Width, panel.Height);
            imageSketchManager.Options.Disposed += ImageSketchManagerOptionsDisposed;
            // workaround to give the key events to imageSketchManager.imageSketchControl
            KeyDown += OnKeyDown;
            KeyUp += OnKeyUp;
            InitOptions(imageSketchManager.Options, false);

            // change from panel to ImageSketchControl
            panel.Visible = false;
            imageSketchManager.ImageSketchControl.Location = panel.Location;
            Controls.Add(imageSketchManager.ImageSketchControl);
        }

        // workaround to give the key events to imageSketchManager.imageSketchControl
        private void OnKeyDown(object sender, KeyEventArgs keyEventArgs)
        {
            imageSketchManager.ImageSketchControl.KeyDownEvent(
                sender, keyEventArgs);
        }

        // workaround to give the key events to imageSketchManager.imageSketchControl
        private void OnKeyUp(object sender, KeyEventArgs keyEventArgs)
        {
            imageSketchManager.ImageSketchControl.KeyUpEvent(
                sender, keyEventArgs);
        }

        void ImageSketchManagerOptionsDisposed(object sender, EventArgs e)
        {
            // workaround to give the key events to imageSketchManager.imageSketchControl
            KeyDown -= OnKeyDown;
            KeyUp -= OnKeyUp;

            // change to panel
            Controls.Remove(imageSketchManager.ImageSketchControl);
            panel.Visible = true;
        }

        #endregion ImageSketches

        private void SplitColorSpaceChannelsToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new SplitColorSpaceChannelsForm(processor).Options, false);
        }

        private void ColorEliminatedRegionGrowingToolStripMenuItemClick(object sender, EventArgs e)
        {
            // InitOptions(new NSColorEliminatedRegionGrowingForm(processor).Options);
        }

        private void ConGrapLightToolStripMenuItemClick(object sender, EventArgs e)
        {
            // InitOptions(new NSConGrapLightForm(processor).Options);
        }

        private void KeyPointBasedFloodFillToolStripMenuItemClick(object sender, EventArgs e)
        {
            // InitOptions(new NSKeyPointAndColorBasedSegmentationForm(processor).Options);
        }

        private void ColorSegmentationToolStripMenuItemClick(object sender, EventArgs e)
        {
            InitOptions(new ColorSegmentationForm(processor).Options, false);
        }

        private void SimpleColorSegmentationToolStripMenuItemClick(object sender, EventArgs e)
        {
            // InitOptions(new NSSimpleColorSegmentationForm(processor).Options);
        }

        private void SimpleDilatationToolStripMenuItemClick(object sender, EventArgs e)
        {
            // InitOptions(new NSSimpleDilatationForm(processor).Options);
        }

        private void SimpleLuvColorbasedSegmentationToolStripMenuItemClick(object sender, EventArgs e)
        {
            // InitOptions(new NSSimpleLuvColorSegmentationForm(processor).Options);
        }

        #endregion Scientific filters ToolStrip MenuItem Events

        #region Drag and drop and mouse events
        private void PanelMouseMove(object sender, MouseEventArgs e)
        {
            int mouseX = panel.PointToClient(Cursor.Position).X;
            int mouseY = panel.PointToClient(Cursor.Position).Y;
            lbX.Text = (Math.Round(mouseX * scaleCursorX + 0.5f)).ToString(
                CultureInfo.InvariantCulture);
            lbY.Text = (Math.Round(mouseY * scaleCursorY + 0.5f)).ToString(
                CultureInfo.InvariantCulture);
        }

        private void ProcessorFormDragDrop(object sender, DragEventArgs dea)
        {
            if (dea.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])dea.Data.GetData(DataFormats.FileDrop);
                Initialize(files[0]); // only first element of drag objects
            }
        }

        private void ProcessorFormDragOver(object sender, DragEventArgs dea)
        {
            if (dea.Data.GetDataPresent(DataFormats.FileDrop))
                dea.Effect = DragDropEffects.Move;
        }
        #endregion Drag and drop and mouse events

        private void CbRealtimeProcessingCheckedChanged(object sender, EventArgs e)
        {
            CheckBox cb = cbRealtimeProcessing;
            processor.RealtimeProcessing = cb.Checked;
            processor.GbProcess.Enabled = !cb.Checked;
            string s = "RealtimeProcessing;" + cb.Checked;
            IOFile.WriteLine(Program.OptionsFile, 3, s, true);
        }

        private void MainFormFormClosing(object sender, FormClosingEventArgs e)
        {
            File.Delete(Program.OptionsPath + "\\black.png");
            saveImageDialogForm.CloseReally();
        }

        #endregion private methods
    }
}
